﻿using System;
using System.Collections.Generic;
using System.Data;

using NUnit.Framework;

namespace Pvax.Data.Tests
{
    /// <summary>
    /// This the <see cref="DbConnectionExtender"/> test uses <see cref="OptimizedPerson"/> and
    /// <see cref="OptimizedPhone"/> classes.
    /// </summary>
    public abstract class OptimizedTestDbConnectionExtender: TestBase
    {
        protected IDbConnection connection;

        // Must initialize the connection
        protected abstract void InitializeConnection();

        [SetUp]
        public void Init()
        {
            InitializeConnection();
            connection.Open();
        }

        [TearDown]
        public void Done()
        {
            ExecuteSql(connection, "DELETE FROM OptimizedPersons WHERE Id=42");
            ExecuteSql(connection, "DELETE FROM OptimizedPhones WHERE Id=100");
            connection.Close();
            connection = null;
        }

        [Test]
        public void OptimizedTestSelectAllPersons()
        {
            List<OptimizedPerson> people = new List<OptimizedPerson>();
            foreach(var person in connection.GetAll<OptimizedPerson>())
                people.Add(person);
            Assert.AreEqual(4, people.Count);
            Assert.AreEqual(1, people[0].Id);
            Assert.AreEqual(2, people[1].Id);
        }

        [Test]
        public void OptimizedTestSelectAllPhones()
        {
            List<OptimizedPhone> phones = new List<OptimizedPhone>();
            foreach(var phone in connection.GetAll<OptimizedPhone>())
                phones.Add(phone);
            Assert.AreEqual(3, phones.Count);
            Assert.AreEqual(1, phones[0].Id);
            Assert.AreEqual(2, phones[1].Id);
            Assert.AreEqual(3, phones[2].Id);
            Assert.AreEqual(1, phones[0].PersonId);
            Assert.AreEqual(1, phones[1].PersonId);
            Assert.AreEqual(2, phones[2].PersonId);
        }

        [Test]
        public void OptimizedTestSelectPersonById()
        {
            var person = connection.Get<OptimizedPerson, long>(2);
            Assert.AreEqual("Ender", person.FirstName);
        }

        [Test]
        public void OptimizedTestSelectPhoneById()
        {
            var phone = connection.Get<OptimizedPhone, long>(2);
            Assert.AreEqual(811, phone.AreaCode);
        }

        [Test]
        public void OptimizedTestSelectPeopleByFirstName()
        {
            List<OptimizedPerson> people = new List<OptimizedPerson>();
            foreach(var person in connection.GetBy<OptimizedPerson>("FirstName", "Ender"))
                people.Add(person);
            Assert.AreEqual(1, people.Count);
            Assert.AreEqual("Wiggin", people[0].LastName);
        }

        [Test]
        public void OptimizedTestSelectPhonesByAreaCode()
        {
            List<OptimizedPhone> phones = new List<OptimizedPhone>();
            foreach(var phone in connection.GetBy<OptimizedPhone>("AreaCode", 811))
                phones.Add(phone);
            Assert.AreEqual(2, phones.Count);
        }

        [Test]
        public void OptimizedTestInsertPersonWithSelect()
        {
            var person = new OptimizedPerson()
            {
                Id = 42,
                FirstName = "Douglas",
                MiddleName = String.Empty,
                LastName = "Adams"
            };
            connection.Add(person);
            person = null;
            person = connection.Get<OptimizedPerson, long>(42);
            Assert.AreEqual("Douglas", person.FirstName);
            Assert.AreEqual("Adams", person.LastName);
        }

        [Test]
        public void OptimizedTestInsertPhoneWithSelect()
        {
            var phone = new OptimizedPhone()
            {
                Id = 100,
                CountryCode = 1,
                AreaCode = 555,
                Number = "4325671"
            };
            connection.Add(phone);
            phone = null;
            phone = connection.Get<OptimizedPhone, long>(100);
            Assert.AreEqual("4325671", phone.Number);
            Assert.AreEqual(555, phone.AreaCode);
        }

        [Test]
        public void OptimizedTestUpdatePerson()
        {
            // As in TestSelectPersonById()
            var person = connection.Get<OptimizedPerson, long>(2);
            Assert.AreEqual("Ender", person.FirstName);
            person.FirstName = "Michael";
            person.MiddleName = String.Empty;
            person.LastName = "Chrichton";
            connection.Put<OptimizedPerson>(person);
            person = connection.Get<OptimizedPerson, long>(2);
            Assert.AreEqual("Michael", person.FirstName);
            Assert.AreEqual(String.Empty, person.MiddleName);
            Assert.AreEqual("Chrichton", person.LastName);
        }

        [Test]
        public void OptimizedTestUpdatePhone()
        {
            // As in TestSelectPhoneById()
            var phone = connection.Get<OptimizedPhone, long>(2);
            Assert.AreEqual(811, phone.AreaCode);
            phone.CountryCode = 7;
            phone.AreaCode = 312;
            phone.Number = "9296739";
            connection.Put<OptimizedPhone>(phone);
            phone = connection.Get<OptimizedPhone, long>(2);
            Assert.AreEqual(7, phone.CountryCode);
            Assert.AreEqual(312, phone.AreaCode);
            Assert.AreEqual("9296739", phone.Number);
        }

        [Test]
        public void OptimizedTestDeletePersonById()
        {
            ExecuteSql(connection, "INSERT INTO OptimizedPersons (Id) VALUES (42)");
            var person = connection.Get<OptimizedPerson, long>(42);
            connection.Remove(person);
            person = connection.Get<OptimizedPerson, long>(42);
            Assert.IsNull(person);
        }

        [Test]
        public void OptimizedTestDeletePhoneById()
        {
            ExecuteSql(connection, "INSERT INTO OptimizedPhones (Id,PersonId,CountryCode,AreaCode) VALUES (42,1,0,0)");
            var phone = connection.Get<OptimizedPhone, long>(42);
            connection.Remove(phone);
            phone = connection.Get<OptimizedPhone, long>(42);
            Assert.IsNull(phone);
        }

        [Test]
        public void OptimizedTestDeletePerson()
        {
            ExecuteSql(connection, "INSERT INTO OptimizedPersons (Id) VALUES (42)");
            var person = new OptimizedPerson()
            {
                Id = 42
            };
            connection.Remove(person);
            person = connection.Get<OptimizedPerson, long>(42);
            Assert.IsNull(person);
        }

        [Test]
        public void OptimizedTestDeletePhone()
        {
            ExecuteSql(connection, "INSERT INTO OptimizedPhones (Id,PersonId,CountryCode,AreaCode) VALUES (42,1,0,0)");
            var phone = new OptimizedPhone()
            {
                Id = 42
            };
            connection.Remove(phone);
            phone = connection.Get<OptimizedPhone, long>(42);
            Assert.IsNull(phone);
        }
    }
}
